package pl.szpadel.android.gadu;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.TreeSet;

import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;

/// data->I bridge for Contact List
public class ContactListAdapter extends DataSetObserver implements ListAdapter {
	
	static final private String TAG = "ContactListAdapter";
	

	/// Data source
	ContactInfoManager mManager;
	
	/// Ordered contacts
	private ArrayList<ContactInfo> mByOrdinal = new ArrayList<ContactInfo>();
	
	/// Set of observes. We need no more than one instance of every observer
	private HashSet<DataSetObserver> mObservers = new HashSet<DataSetObserver>();

	
	/// Initilaizing constructor. Provides contact list manager - the actual data source
	ContactListAdapter(ContactInfoManager manager) {
		assert(manager != null);
		
		mManager  = manager;
		mManager.registerDataSetObserver(this);
		rebuildIndex();
	}
	
	@Override
	public int getCount() {
		return mByOrdinal.size();
	}

	@Override
	public Object getItem(int position) {
		return mByOrdinal.get(position);
	}

	@Override
	public long getItemId(int position) {
		return mByOrdinal.get(position).id;
	}

	@Override
	public int getItemViewType(int position) {
		// All items are presented using the same type
		// this may change once grouping is introduced
		return 0;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View v = null;
		// reuse previous view if possible
		if (convertView != null) {
			v = convertView;
		} else {
			LayoutInflater inflater = LayoutInflater.from(parent.getContext());
			v = inflater.inflate(R.layout.user_list_item, null);
		}
		
		// populate the view
		TextView name = (TextView)v.findViewById(R.id.DisplayedName);
		TextView status = (TextView)v.findViewById(R.id.Status);
		ImageView statusIcon = (ImageView)v.findViewById(R.id.StatusIcon);
		
		ContactInfo info = mByOrdinal.get(position);
		
		name.setText(info.displayName);
		status.setText(info.status.getDescription());
		
		// find image resource
		int res = info.status.getIcon();
		statusIcon.setImageResource(res);
		
		return v;
	}

	@Override
	public int getViewTypeCount() {
		return 1;
	}

	@Override
	public boolean hasStableIds() {
		return true;
	}

	@Override
	public synchronized boolean isEmpty() {
		return mByOrdinal.isEmpty();
	}

	@Override
	public boolean areAllItemsEnabled() {
		return true;
	}

	@Override
	public boolean isEnabled(int position) {
		return true;
	}
	 

	@Override
	public void registerDataSetObserver(DataSetObserver observer) {
		mObservers.add(observer);
	}

	@Override
	public void unregisterDataSetObserver(DataSetObserver observer) {
		mObservers.remove(observer);
		
	}
	
	@Override
	public void onChanged() {
		rebuildIndex();
	}
	
	
	///////////////////////////////////////////
	// index
	
	/// Comparator for ContactInfo
	/// compares by: 'offliness', display name, gg number
	private class ContactInfoComparator implements Comparator<ContactInfo> {

		@Override
		public int compare(ContactInfo arg0, ContactInfo arg1) {
			// first - online before offline
			AGLog.d(TAG, "Comparing statuses: " + arg0.displayName + ":" + arg0.status + " online: " + arg0.status.isOnline() + " vs " 
					+ arg1.displayName + ":" + arg1.status + " online: " + arg1.status.isOnline());
			
			if (arg0.status.isOnline() && !arg1.status.isOnline()) {
				AGLog.d(TAG, "-1");
				return -1;
			} else if (!arg0.status.isOnline() && arg1.status.isOnline()) {
				AGLog.d(TAG, "+1");
				return +1;
			} else {
				int stringRes = arg0.displayName.compareToIgnoreCase(arg1.displayName);
				if (stringRes != 0) {
					AGLog.d(TAG, "by name: " + stringRes);
					return stringRes;
				} else {
					AGLog.d(TAG, "by uin: " + (int)(arg0.id - arg1.id));
					return (int)(arg0.id - arg1.id);
				}
			}
		}
	}
	
	/// Rebuilds index after underlying dataset change
	private void rebuildIndex() {
		try {
			assert(mManager != null);
			
			TreeSet<ContactInfo> sortingSet = new TreeSet<ContactInfo>(new ContactInfoComparator());
			
			/// copy from manager to sorting set
			sortingSet.addAll(mManager.getContacts());
	
			// compe from sorting set to index
			mByOrdinal.clear();
			for (ContactInfo ci : sortingSet) {
				mByOrdinal.add(ci);
			}
			
			notifyObservers();
		} catch (Exception e) {
			AGLog.e(TAG, "Error rebuilding index: " + e.getMessage());
		}
	}
	
	/// Notifies observers of change
	private void notifyObservers() {
		for (DataSetObserver observer : mObservers ) {
			observer.onChanged();
		}
	}

}
